/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package es.unavarra.mti.iws.logic;

import es.unavarra.mti.iws.Manager;
import es.unavarra.mti.iws.gui.MainFrame;
import es.unavarra.mti.iws.model.Event;
import es.unavarra.mti.iws.model.Fire;
import es.unavarra.mti.iws.model.Model;
import es.unavarra.mti.iws.model.Node;
import es.unavarra.mti.iws.model.Quake;
import es.unavarra.mti.iws.model.Rain;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

/**
 *
 * @author Asier
 */
public class EngineEvaluator extends Thread {
    public static final float FPS = 0.1f;

    private Manager manager;
    private boolean stoped,running,step;
    private long lastNanos,sleepNanos;


    public EngineEvaluator(Manager manager) {
        this.manager = manager;
    }

    @Override
    public void run() {
        while(!stoped){
            try{
                lastNanos = System.nanoTime();
                if(running || step){
                    doRun();
                    step = false;
                }else{
                    synchronized(this) {
                        try { wait();} catch (InterruptedException ex) {}
                    }
                }
                sleepNanos = Math.round( (1000000000.0/FPS) - (System.nanoTime() - lastNanos) );
                if(sleepNanos > 0){
                    LockSupport.parkNanos(sleepNanos);
                }else{
                    yield();
                }
            }catch(Exception ex){
                MainFrame.getInstance().error("EngineEvaluator " + ex.toString());
                ex.printStackTrace();
                pause();
            }
        }
    }

    public void pause(){
        running = false;
    }

    public void play(){
        running = true;
        synchronized(this){
            this.notifyAll();
        }
    }

    public void end() {
        stoped = true;
        try { interrupt(); }catch(Exception e){}
    }


    private void doRun() {
        Model m = manager.getModel();
        if(m == null){ return; }
        synchronized(m){
            synchronized(m.getNodes()){
                HashMap<String,Node> nodes = new HashMap<String, Node>(m.getNodes().size());
                for(Node n : m.getNodes()){
                    nodes.put(n.getId(), n);
                    n.setHasFire(false); n.setHasQuake(false); n.setHasRain(false);
                    n.setFire(0.0f); n.setQuake(0.0f); n.setRain(0.0f);
                    synchronized(m.getEvents()){
                        for(Event e : m.getEvents()){
                            if(collide(n, e)){
                                if(e instanceof Fire){
                                    n.setFire( n.getFire() + ((Fire)e).getTemperature());
                                }else if(e instanceof Quake){
                                    n.setQuake( n.getFire() + ((Quake)e).getScale());
                                }else if(e instanceof Rain){
                                    n.setRain( n.getFire() + ((Rain)e).getLitres());
                                }
                            }
                        }
                    }
                    manager.getEngine().setTemp(n.getId(), n.getFire());
                    manager.getEngine().setRain(n.getId(), n.getRain());
                    manager.getEngine().setTilt(n.getId(), n.getQuake());
                }
                
                List<String> withFire = manager.getEngine().burnedNodes();
                List<String> withRain = manager.getEngine().wetNodes();
                List<String> withQuake = manager.getEngine().fallenNodes();
                if(withFire != null){
                    for(String s : withFire){
                        s = extractNodeName(s);
                        Node n = nodes.get(s);
                        if(n != null) { n.setHasFire(true); }
                    }
                }
                if (withRain != null) {
                    for (String s : withRain) {
                        s = extractNodeName(s);
                        Node n = nodes.get(s);
                        if (n != null) {
                            n.setHasRain(true);
                        }
                    }
                }
                if (withQuake != null) {
                    for (String s : withQuake) {
                        s = extractNodeName(s);
                        Node n = nodes.get(s);
                        if (n != null) {
                            n.setHasQuake(true);
                        }
                    }
                }

            }
        }
    }

    private String extractNodeName(String s){
        int index = s.lastIndexOf("#");
        if(index != -1 && index+1 < s.length()){
            return s.substring(index+1);
        }
        return s;
    }

    private boolean collide(Node n, Event e){
        float dx = n.getX() - e.getX();
        float dy = n.getY() - e.getY();
        float nodeRadious = (n.getSizeX() + n .getSizeY()) / 4.0f;
        return Math.sqrt(dx*dx+dy*dy) < nodeRadious+e.getRadious();
    }

}
